
import "DPI-C" function void generate_memory_region();
// import "DPI-C" function void generate_memory_region(input string elf_name);
import "DPI-C" function void access_memory_subsystem(
  							input     bit         reset,
                            input     bit[63:0]   sim_cycles,
                            input     bit         axi_aw_valid,
  							output    bit         axi_aw_ready,
  							input     bit[47:0]   axi_aw_addr,
  							input     bit[4:0]    axi_aw_id,
  							input     bit[7:0]    axi_aw_len,
  							input     bit[2:0]    axi_aw_size,
  							input     bit[1:0]    axi_aw_burst,
  							input     bit[3:0]    axi_aw_cache,
  							input     bit[2:0]    axi_aw_prot,
  							input     bit         axi_w_valid,
  							output    bit         axi_w_ready,
  							input     bit[127:0]  axi_w_data,
  							input     bit[15:0]   axi_w_strb,
  							input     bit         axi_w_last,
  							output    bit         axi_b_valid,
  							input     bit         axi_b_ready,
  							output    bit[4:0]    axi_b_id,
  							output    bit[1:0]    axi_b_resp,
  							input     bit         axi_ar_valid,
  							output    bit         axi_ar_ready,
  							input     bit[47:0]   axi_ar_addr,
  							input     bit[4:0]    axi_ar_id,
  							input     bit[7:0]    axi_ar_len,
  							input     bit[2:0]    axi_ar_size,
  							input     bit[1:0]    axi_ar_burst,
  							input     bit[3:0]    axi_ar_cache,
  							input     bit[2:0]    axi_ar_prot,
  							output    bit         axi_r_valid,
  							input     bit         axi_r_ready,
  							output    bit[127:0]  axi_r_data,
  							output    bit[4:0]    axi_r_id,
  							output    bit[1:0]    axi_r_resp,
  							output    bit         axi_r_last);


// import uvm_pkg::*;

// `include "uvm_macros.svh"
// Top Module for VCS and Verdi
module top_testharness();

// static uvm_cmdline_processor uvcl = uvm_cmdline_processor::get_inst();

string binary = "vmlinx";

wire   [1:0]    core_in_core_id;
wire   [7:0]    core_in_interrupt;
wire            core_in_ipi;
wire            uart_txd;


bit            axi_aw_valid;
reg            axi_aw_ready;
bit   [47:0]   axi_aw_addr;
bit   [4:0]    axi_aw_id;
bit   [7:0]    axi_aw_len;
bit   [2:0]    axi_aw_size;
bit   [1:0]    axi_aw_burst;
bit   [3:0]    axi_aw_cache;
bit   [2:0]    axi_aw_prot;
bit            axi_w_valid;
reg            axi_w_ready;
bit   [127:0]  axi_w_data;
bit   [15:0]   axi_w_strb;
bit            axi_w_last;
reg            axi_b_valid;
bit            axi_b_ready;
reg   [4:0]    axi_b_id;
reg   [1:0]    axi_b_resp;
bit            axi_ar_valid;
reg            axi_ar_ready;
bit   [47:0]   axi_ar_addr;
bit   [4:0]    axi_ar_id;
bit   [7:0]    axi_ar_len;
bit   [2:0]    axi_ar_size;
bit   [1:0]    axi_ar_burst;
bit   [3:0]    axi_ar_cache;
bit   [2:0]    axi_ar_prot;
reg            axi_r_valid;
bit            axi_r_ready;
reg   [127:0]  axi_r_data;
reg   [4:0]    axi_r_id;
reg   [1:0]    axi_r_resp;
reg            axi_r_last;



reg clk;
initial begin 
  clk = 0;
  forever begin
    #(2) clk = ~clk;
  end
end

reg reset;
initial begin
  reset = 1;
  #10;
  reset = 1;
  #80;
  reset = 0;
end

`define  DUMMY_LOG

reg [47:0] cpu_awaddr;
reg [3:0]  cpu_awlen;
reg [15:0] cpu_wstrb;
reg        cpu_wvalid;
reg        cpu_wready;
reg [63:0] value0;
reg [63:0] value1;
reg [63:0] value2;


`ifdef DUMMY_LOG

always @(posedge clk)
begin
  cpu_awlen[3:0]   <= axi_aw_len[3:0];
  cpu_awaddr[47:0] <= axi_aw_addr[47:0];
  cpu_wvalid       <= axi_w_valid;
  cpu_wready       <= axi_w_ready;
  cpu_wstrb        <= axi_w_strb;
  value0           <= axi_w_data[63:0];
  value1           <= axi_w_data[127:64];
end


always @(posedge clk) begin
     if ((cpu_awlen[3:0] == 4'b0) &&
         (cpu_awaddr[31:0] == 32'h1FF1_0000) &&
          cpu_wvalid &&
          cpu_wready
     ) begin
        if(cpu_wstrb[15:0] == 16'hf) 
           begin
              $write("%c", axi_w_data[7:0]);
           end
        else if(cpu_wstrb[15:0] == 16'hf0)
           begin
              $write("%c", axi_w_data[39:32]);
           end
        else if(cpu_wstrb[15:0] == 16'hf00)
           begin
              $write("%c", axi_w_data[71:64]);
           end
        else if(cpu_wstrb[15:0] == 16'hf000)
           begin
              $write("%c", axi_w_data[103:96]);
           end
    end
end
`endif


assign core_in_core_id = {1'b0, 1'b0};
assign core_in_interrupt = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};
assign core_in_ipi = 1'b0;


reg sys_exit;

`ifdef DUMMY_LOG
always @(posedge clk) begin
     if ((cpu_awaddr[31:0] == 32'h1FF8_0000) &&
          cpu_wvalid &&
          cpu_wready
     ) begin
        if(cpu_wstrb[15:0] == 16'hff &&
            axi_w_data[7:0] == 8'b00001111) 
           begin
              sys_exit <= 1;
              $finish;
           end
    end
end
`endif


`ifdef VERDI_DUMP
initial begin
      /// method 1: this will dump only ct_top module
      $fsdbDumpon;
      $fsdbDumpvars(0, top_testharness);

      /// method 2: this will dump all module
      // $fsdbDumpvars();
end
`endif

assign axi_aw_cache = 0;
assign axi_aw_prot = 0;
assign axi_ar_cache = 0;
assign axi_ar_prot = 0;

bit            axi_aw_ready_t;
bit            axi_w_ready_t;
bit            axi_b_valid_t;
bit   [4:0]    axi_b_id_t;
bit   [1:0]    axi_b_resp_t;
bit            axi_ar_ready_t;
bit            axi_r_valid_t;
bit   [127:0]  axi_r_data_t;
bit   [4:0]    axi_r_id_t;
bit   [1:0]    axi_r_resp_t;
bit            axi_r_last_t;

top_wrap Top_wrap(
        .clk                (clk),
	    .reset              (reset),
        .axi_aw_valid       (axi_aw_valid),
        .axi_aw_ready       (axi_aw_ready),
        .axi_aw_addr        (axi_aw_addr),
        .axi_aw_id          (axi_aw_id),
        .axi_aw_len         (axi_aw_len),
        .axi_aw_size        (axi_aw_size),
        .axi_aw_burst       (axi_aw_burst),
        // .axi_aw_cache    (axi_aw_cache),
        // .axi_aw_prot     (axi_aw_prot),
        .axi_w_valid        (axi_w_valid),
        .axi_w_ready        (axi_w_ready),
        .axi_w_data         (axi_w_data),
        .axi_w_strb         (axi_w_strb),
        .axi_w_last         (axi_w_last),
        .axi_b_valid        (axi_b_valid),
        .axi_b_ready        (axi_b_ready),
        .axi_b_id           (axi_b_id),
        // .axi_b_resp      (axi_b_resp),
        .axi_ar_valid       (axi_ar_valid),
        .axi_ar_ready       (axi_ar_ready),
        .axi_ar_addr        (axi_ar_addr),
        .axi_ar_id          (axi_ar_id),
        .axi_ar_len         (axi_ar_len),
        .axi_ar_size        (axi_ar_size),
        .axi_ar_burst       (axi_ar_burst),
        // .axi_ar_cache(axi_ar_cache),
        // .axi_ar_prot(axi_ar_prot),
        .axi_r_valid        (axi_r_valid),
        .axi_r_ready        (axi_r_ready),
        .axi_r_data         (axi_r_data),
        .axi_r_id           (axi_r_id),
        // .axi_r_resp      (axi_r_resp),
        .axi_r_last         (axi_r_last),
        .core_in_core_id    (core_in_core_id),
        .core_in_interrupt  (core_in_interrupt),
        .core_in_ipi        (core_in_ipi)
    );


initial begin
  // void'(uvcl.get_arg_value("+PRELOAD=", binary));
  // if (binary != "") begin
  // generate_memory_region(binary);
  generate_memory_region();
  // end

  // fork
  //   forever @(posedge clk) begin
  //     	access_memory_subsystem(reset,
  //     		axi_aw_valid,axi_aw_ready,axi_aw_addr,axi_aw_id,axi_aw_len,axi_aw_size,axi_aw_burst,axi_aw_cache,axi_aw_prot,
  // 			axi_w_valid,axi_w_ready,axi_w_data,axi_w_strb,axi_w_last,
  // 			axi_b_valid,axi_b_ready,axi_b_id,axi_b_resp,
  // 			axi_ar_valid,axi_ar_ready,axi_ar_addr,axi_ar_id,axi_ar_len,axi_ar_size,axi_ar_burst,axi_ar_cache,axi_ar_prot,
  // 			axi_r_valid,axi_r_ready,axi_r_data,axi_r_id,axi_r_resp,axi_r_last
  //     		);
  //   end
  // join_none
end


reg [63:0] sim_cycles;

always @(posedge clk) begin : proc_sim_cycles
    if(reset) begin
        sim_cycles <= 0;
    end else begin
        sim_cycles <= sim_cycles + 1'b1;
    end
end


bit            axi_aw_ready_t;
bit            axi_w_ready_t;
bit            axi_b_valid_t;
bit   [4:0]    axi_b_id_t;
bit   [1:0]    axi_b_resp_t;
bit            axi_ar_ready_t;
bit            axi_r_valid_t;
bit   [127:0]  axi_r_data_t;
bit   [4:0]    axi_r_id_t;
bit   [1:0]    axi_r_resp_t;
bit            axi_r_last_t;


reg            axi_aw_valid_t;
reg   [47:0]   axi_aw_addr_t;
reg   [4:0]    axi_aw_id_t;
reg   [7:0]    axi_aw_len_t;
reg   [2:0]    axi_aw_size_t;
reg   [1:0]    axi_aw_burst_t;
reg   [3:0]    axi_aw_cache_t;
reg   [2:0]    axi_aw_prot_t;
reg            axi_w_valid_t;
reg   [127:0]  axi_w_data_t;
reg   [15:0]   axi_w_strb_t;
reg            axi_w_last_t;
reg            axi_b_ready_t;
reg            axi_ar_valid_t;
reg   [47:0]   axi_ar_addr_t;
reg   [4:0]    axi_ar_id_t;
reg   [7:0]    axi_ar_len_t;
reg   [2:0]    axi_ar_size_t;
reg   [1:0]    axi_ar_burst_t;
reg   [3:0]    axi_ar_cache_t;
reg   [2:0]    axi_ar_prot_t;
reg            axi_r_ready_t;


// always @(posedge clk) begin
always @(*) begin

//     access_memory_subsystem(reset, sim_cycles, 
//         axi_aw_valid_t,axi_aw_ready_t,axi_aw_addr_t,axi_aw_id_t,axi_aw_len_t,axi_aw_size_t,axi_aw_burst_t,axi_aw_cache_t,axi_aw_prot_t,
//         axi_w_valid_t,axi_w_ready_t,axi_w_data_t,axi_w_strb_t,axi_w_last_t,
//         axi_b_valid_t,axi_b_ready_t,axi_b_id_t,axi_b_resp_t,
//         axi_ar_valid_t,axi_ar_ready_t,axi_ar_addr_t,axi_ar_id_t,axi_ar_len_t,axi_ar_size_t,axi_ar_burst_t,axi_ar_cache_t,axi_ar_prot_t,
//         axi_r_valid_t,axi_r_ready_t,axi_r_data_t,axi_r_id_t,axi_r_resp_t,axi_r_last_t
//         );

//     axi_aw_valid_t <= axi_aw_valid;
//     axi_aw_addr_t <= axi_aw_addr;
//     axi_aw_id_t <= axi_aw_id;
//     axi_aw_len_t <= axi_aw_len;
//     axi_aw_size_t <= axi_aw_size;
//     axi_aw_burst_t <= axi_aw_burst;
//     axi_aw_cache_t <= axi_aw_cache;
//     axi_aw_prot_t <= axi_aw_prot;
//     axi_w_valid_t <= axi_w_valid;
//     axi_w_data_t <= axi_w_data;
//     axi_w_strb_t <= axi_w_strb;
//     axi_w_last_t <= axi_w_last;
//     axi_b_ready_t <= axi_b_ready;
//     axi_ar_valid_t <= axi_ar_valid;
//     axi_ar_addr_t <= axi_ar_addr;
//     axi_ar_id_t <= axi_ar_id;
//     axi_ar_len_t <= axi_ar_len;
//     axi_ar_size_t <= axi_ar_size;
//     axi_ar_burst_t <= axi_ar_burst;
//     axi_ar_cache_t <= axi_ar_cache;
//     axi_ar_prot_t <= axi_ar_prot;
//     axi_r_ready_t <= axi_r_ready;

    // access_memory_subsystem(reset, sim_cycles,
    //         axi_aw_valid,axi_aw_ready_t,axi_aw_addr,axi_aw_id,axi_aw_len,axi_aw_size,axi_aw_burst,axi_aw_cache,axi_aw_prot,
    //         axi_w_valid,axi_w_ready_t,axi_w_data,axi_w_strb,axi_w_last,
    //         axi_b_valid_t,axi_b_ready,axi_b_id_t,axi_b_resp_t,
    //         axi_ar_valid,axi_ar_ready_t,axi_ar_addr,axi_ar_id,axi_ar_len,axi_ar_size,axi_ar_burst,axi_ar_cache,axi_ar_prot,
    //         axi_r_valid_t,axi_r_ready,axi_r_data_t,axi_r_id_t,axi_r_resp_t,axi_r_last_t
    // );

    // axi_aw_ready <= axi_aw_ready_t;
    // axi_w_ready <= axi_w_ready_t;
    // axi_b_valid <= axi_b_valid_t;
    // axi_b_id <= axi_b_id_t;
    // axi_b_resp <= axi_b_resp_t;
    // axi_ar_ready <= axi_ar_ready_t;
    // axi_r_valid <= axi_r_valid_t;
    // axi_r_data <= axi_r_data_t;
    // axi_r_id <= axi_r_id_t;
    // axi_r_resp <= axi_r_resp_t;
    // axi_r_last <= axi_r_last_t;


    access_memory_subsystem(reset, sim_cycles, 
            axi_aw_valid,axi_aw_ready,axi_aw_addr,axi_aw_id,axi_aw_len,axi_aw_size,axi_aw_burst,axi_aw_cache,axi_aw_prot,
            axi_w_valid,axi_w_ready,axi_w_data,axi_w_strb,axi_w_last,
            axi_b_valid,axi_b_ready,axi_b_id,axi_b_resp,
            axi_ar_valid,axi_ar_ready,axi_ar_addr,axi_ar_id,axi_ar_len,axi_ar_size,axi_ar_burst,axi_ar_cache,axi_ar_prot,
            axi_r_valid,axi_r_ready,axi_r_data,axi_r_id,axi_r_resp,axi_r_last
    );




end

// always @(*) begin : proc_
//     axi_aw_ready = axi_aw_ready_t;
//     axi_w_ready = axi_w_ready_t;
//     axi_b_valid = axi_b_valid_t;
//     axi_b_id = axi_b_id_t;
//     axi_b_resp = axi_b_resp_t;
//     axi_ar_ready = axi_ar_ready_t;
//     axi_r_valid = axi_r_valid_t;
//     axi_r_data = axi_r_data_t;
//     axi_r_id = axi_r_id_t;
//     axi_r_resp = axi_r_resp_t;
//     axi_r_last = axi_r_last_t;
// end


endmodule